﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using ibba.src.sl.recursos.MVVM;

namespace ibba.src.noriskbo.code
{
    /// <summary>
    /// Classe auxiliar para popular e manipular uma lista de registros
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DetailsAux<T> : INotifyPropertyChanged 
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));

        }

        #endregion

        public delegate void EventLoadDetails();
        public event EventLoadDetails OnLoadDetails;

        public delegate void EventChangeDetails();
        public event EventChangeDetails OnChangeDetails;

        public delegate void EventChangeDetailSelected();
        public event EventChangeDetailSelected OnChangeDetailSelected;

        public delegate void EventChangeFlagAcaoSQL(object sender, Enums.TipoAcaoSQL oldType, Enums.TipoAcaoSQL newType);
        public event EventChangeFlagAcaoSQL OnChangeFlagAcaoSQL;


        public DetailsAux()
        {
            ListaOC = new ObservableCollection<T>();            
        }

        protected Enums.TipoAcaoSQL GetTipoAcaoSQL(object pDetalhe)
        {
            return (Enums.TipoAcaoSQL)pDetalhe.GetType().GetProperty("FlagAcaoSQL").GetValue(pDetalhe, null);
        }
        protected void SetTipoAcaoSQL(object pDetalhe, Enums.TipoAcaoSQL pTipo)
        {
            var old = GetTipoAcaoSQL(pDetalhe);

            pDetalhe.GetType().GetProperty("FlagAcaoSQL").SetValue(pDetalhe, (int)pTipo, null);

            if (OnChangeFlagAcaoSQL != null)
                OnChangeFlagAcaoSQL(pDetalhe, old, pTipo);
        }

        public void CarregarDetalhes(List<T> pListaEntidade, bool pManterItens)
        {
            if (pManterItens == false)
                ListaOC.Clear();

            ListaOC.AddRange(pListaEntidade);

            if (OnLoadDetails != null)
                OnLoadDetails();
        }

        public List<T> ListaParaSalvar()
        {
            return ListaOC.Where(e => !GetTipoAcaoSQL(e).Equals(Enums.TipoAcaoSQL.None)).ToList();
        }


        public ObservableCollection<T> ListaOC { get; private set; }
        private T _DetalheSelecionado;
        public T DetalheSelecionado
        {
            get
            {
                return _DetalheSelecionado;
            }
            set
            {
                _DetalheSelecionado = value;
                RaisePropertyChanged("DetalheSelecionado");

                if (OnChangeDetailSelected != null)
                    OnChangeDetailSelected();
            }
        }

        private PagedCollectionView _colecao;
        public PagedCollectionView Colecao
        {
            get 
            {
                if (_colecao == null)
                    _colecao = new PagedCollectionView(ListaOC);

                return _colecao; 
            }
            set
            {
                if (_colecao != value)
                {
                    _colecao = value;
                    this.RaisePropertyChanged("Colecao");
                }
            }
        }

        //public void EditarDetalhe()
        //{
        //    if (GetTipoAcaoSQL(DetalheSelecionado).Equals(Enums.TipoAcaoSQL.None))
        //    {
        //        SetTipoAcaoSQL(DetalheSelecionado, Enums.TipoAcaoSQL.Update);
        //    }            
        //}

        private DelegateCommand _commandAdd;
        public DelegateCommand CommandAdd
        {
            get
            {
                if (_commandAdd == null)
                    _commandAdd = new DelegateCommand(() => AddDetail());
                //_commandAdd = new DelegateCommand(delegate
                //{
                //    ListaOC.Add(default(T));
                //});
                return _commandAdd;
            }
        }
        public void AddDetail()
        {
            T obj = Activator.CreateInstance<T>();
            SetTipoAcaoSQL(obj, Enums.TipoAcaoSQL.Insert);

            ListaOC.Add(obj);
            if (OnChangeDetails != null)
                OnChangeDetails();
        }

        private DelegateCommand _commandRemove;
        public DelegateCommand CommandRemove
        {
            get
            {
                if (_commandRemove == null)
                    _commandRemove = new DelegateCommand(() => RemoveDetail());

                return _commandRemove;
            }
        }
        public void RemoveDetail()
        {
            if (DetalheSelecionado == null)
            {
                MessageBoxHelper.ShowWarning(AppHelper.NomeSistema, "É necessário selecionar um registro.");
            }
            else
            {
                Deployment.Current.Dispatcher.BeginInvoke(()=>
                {
                    MessageBoxHelper.ShowQuestion(AppHelper.NomeSistema,
                                "Confirma a exclusão do registro selecionado?",
                                (res) =>
                                {
                                    if (res == MessageBoxResult.Yes)
                                    {
                                        CheckRemove();                                        
                                    }
                                });
                    
                });
            }
        }

        private DelegateCommand _commandCheckRemove;
        public DelegateCommand CommandCheckRemove
        {
            get
            {
                if (_commandCheckRemove == null)
                    _commandCheckRemove = new DelegateCommand(()=>CheckRemove());

                return _commandCheckRemove;
            }
        }
        public void CheckRemove()
        {
            Enums.TipoAcaoSQL acaoAtual = GetTipoAcaoSQL(DetalheSelecionado);

            //Se registro selecionado estiver sendo alterado ou já está gravado
            //então marca para exclusão
            if (acaoAtual == Enums.TipoAcaoSQL.None || acaoAtual == Enums.TipoAcaoSQL.Update || acaoAtual == Enums.TipoAcaoSQL.Delete)
            {
                if (acaoAtual == Enums.TipoAcaoSQL.Delete)
                    SetTipoAcaoSQL(DetalheSelecionado, Enums.TipoAcaoSQL.Update);
                else
                    SetTipoAcaoSQL(DetalheSelecionado, Enums.TipoAcaoSQL.Delete);
                
                ApplyFilterCollection();
            }
            else
            {
                //Se for um registro novo apenas remove da lista
                ListaOC.Remove(DetalheSelecionado);

            }

            if (OnChangeDetails != null)
                OnChangeDetails();


        }

        private void ApplyFilterCollection()
        {
            Colecao.Filter = (f) => GetTipoAcaoSQL(f) != Enums.TipoAcaoSQL.Delete;
            Colecao.Refresh();
        }

        public void SaveDetails()
        {
            CarregarDetalhes((from o in ListaOC where GetTipoAcaoSQL(o) != Enums.TipoAcaoSQL.Delete select o).ToList(), false);

            foreach (T obj in ListaOC)
            {
                SetTipoAcaoSQL(obj, Enums.TipoAcaoSQL.None);
            }
        }

    }
}
